home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
src
/
haeberli
/
libgutil
/
path.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
10KB
|
549 lines
/*
* Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
* the contents of this file may not be disclosed to third parties, copied or
* duplicated in any form, in whole or in part, without the prior written
* permission of Silicon Graphics, Inc.
*
* RESTRICTED RIGHTS LEGEND:
* Use, duplication or disclosure by the Government is subject to restrictions
* as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
* and Computer Software clause at DFARS 252.227-7013, and/or in similar or
* successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
* rights reserved under the Copyright Laws of the United States.
*/
/*
* path -
* General functions to support creation of PostScript
* stroked, filled, and beveled paths.
*
* Paul Haeberli - 1990
*/
#include "stdio.h"
#include "gl.h"
#include "sgiobj.h"
#include "vect.h"
#include "path.h"
/* #define MAKETMESHES */
/*
* function prototypes
*
*
*/
extern sgiobj *getfaces();
extern sgiobj *follow();
static void checkpath();
static void addtopath(path *p, pathseg *ps);
static addline(path *p, float x1, float y1, float x2, float y2);
static addcurve(path *p, float x1, float y1, float x2, float y2,
float x3, float y3, float x4, float y4);
static int nfloats(path *p);
static void flattenpath(path *p);
static bezadapt(float x0,float y0,float x1,float y1,
float x2,float y2,float x3,float y3,float beztol,path *p, int startb);
static void entershape(path *p, int dopath);
/*
* global variables
*
*
*/
static float curflatness = -1.0;
static float curx, cury;
static float startx, starty;
static path *curpath;
static path *bevpath;
static int nsegs;
/*
* internal functions
*
*
*/
static void checkpath()
{
if(!curpath) {
curpath = (path *)mymalloc(sizeof(path));
curpath->type = TYPE_BUILD;
curpath->ncurves = 0;
curpath->head=0;
curpath->tail=0;
curpath->data=0;
nsegs = 0;
}
}
static void addtopath(path *p, pathseg *ps)
{
ps->next = 0;
if(p->tail) {
p->tail->next = ps;
p->tail = ps;
} else
p->head = p->tail = ps;
}
static addline(path *p, float x1, float y1, float x2, float y2)
{
pathline *pl;
pl = (pathline *)mymalloc(sizeof(pathline));
pl->x1 = x1;
pl->x2 = x2;
pl->y1 = y1;
pl->y2 = y2;
pl->dx1 = x2-x1;
pl->dy1 = y2-y1;
pl->dx2 = x2-x1;
pl->dy2 = y2-y1;
if(nsegs == 0)
pl->attr = SEG_LINE|START_BIT;
else
pl->attr = SEG_LINE;
addtopath(curpath,(pathseg *)pl);
nsegs++;
}
static addcurve(path *p, float x1, float y1, float x2, float y2,
float x3, float y3, float x4, float y4)
{
pathcurve *pc;
curpath->ncurves++;
pc = (pathcurve *)mymalloc(sizeof(pathcurve));
pc->x1 = x1;
pc->x2 = x2;
pc->x3 = x3;
pc->x4 = x4;
pc->y1 = y1;
pc->y2 = y2;
pc->y3 = y3;
pc->y4 = y4;
if(nsegs == 0)
pc->attr = SEG_CURVE|START_BIT;
else
pc->attr = SEG_CURVE;
addtopath(curpath,(pathseg *)pc);
nsegs++;
}
static int nfloats(path *p)
{
int nf;
pathseg *ps;
path *flatp, fp;
nf = 0;
ps = curpath->head;
while(ps) {
nf += 2;
if(ps->attr & START_BIT) {
nf++;
nf += 2;
}
ps = ps->next;
}
nf++;
return nf;
}
static void flattenpath(path *p)
{
pathseg *ps, *txen, *pstart;
pathcurve *pc;
int startb;
if(curpath->ncurves == 0)
return;
if(curflatness<0.0) {
fprintf(stderr,"must call setflat(flatness) before using curves\n");
exit(1);
}
pstart = p->head;
p->head = p->tail = 0;
ps = pstart;
while(ps) {
txen = ps->next;
ps = txen;
}
ps = pstart;
while(ps) {
txen = ps->next;
if((ps->attr&SEG_MASK) == SEG_LINE) {
addtopath(p,ps);
} else {
startb = ps->attr & START_BIT;
pc = (pathcurve *)ps;
bezadapt(pc->x1,pc->y1,pc->x2,pc->y2,
pc->x3,pc->y3,pc->x4,pc->y4,curflatness,p,startb);
free(ps);
}
ps = txen;
}
p->ncurves = 0;
}
static bezadapt(float x0,float y0,float x1,float y1,
float x2,float y2,float x3,float y3,float beztol,path *p, int startb)
{
float ax0,ay0,ax1,ay1,ax2,ay2,ax3,ay3;
float bx0,by0,bx1,by1,bx2,by2,bx3,by3;
float midx, midy;
float linx, liny, dx, dy, mag;
pathline *pl;
midx = (x0+3*x1+3*x2+x3)/8.0;
midy = (y0+3*y1+3*y2+y3)/8.0;
linx = (x0+x3)/2.0;
liny = (y0+y3)/2.0;
dx = midx-linx;
dy = midy-liny;
mag = dx*dx+dy*dy;
if(mag<(beztol*beztol)) {
/* drawline(x0,y0,x3,y3,x1-x0,y1-y0,x3-x2,y3-y2); */
pl = (pathline *)mymalloc(sizeof(pathline));
pl->x1 = x0;
pl->y1 = y0;
pl->x2 = x3;
pl->y2 = y3;
pl->dx1 = x1-x0;
pl->dy1 = y1-y0;
pl->dx2 = x3-x2;
pl->dy2 = y3-y2;
if(startb) {
pl->attr = SEG_LINE|START_BIT;
} else
pl->attr = SEG_LINE;
addtopath(p,(pathseg *)pl);
} else {
ax0 = x0;
ay0 = y0;
ax1 = (x0+x1)/2.0;
ay1 = (y0+y1)/2.0;
ax2 = (x0+2.0*x1+x2)/4.0;
ay2 = (y0+2.0*y1+y2)/4.0;
ax3 = midx;
ay3 = midy;
bezadapt(ax0,ay0,ax1,ay1,ax2,ay2,ax3,ay3,beztol,p,startb);
bx0 = midx;
by0 = midy;
bx1 = (x1+2.0*x2+x3)/4.0;
by1 = (y1+2.0*y2+y3)/4.0;
bx2 = (x2+x3)/2.0;
by2 = (y2+y3)/2.0;
bx3 = x3;
by3 = y3;
bezadapt(bx0,by0,bx1,by1,bx2,by2,bx3,by3,beztol,p,0);
}
}
static void entershape(path *p, int dopath)
{
vect s, l, c;
vect ds, dl, dc;
int nsides;
pathline *pl;
pl = (pathline *)p->head;
if(dopath)
pathbegin();
else
tempbegin();
nsides = 0;
while(pl) {
if(pl->attr & START_BIT) {
if(nsides>0 && dopath) {
if(c.x != s.x || c.y != s.y)
mypathsegment(&c,&dc,&s,&ds);
pathclose();
}
nsides = 0;
}
l.x = pl->x1;
l.y = pl->y1;
dl.x = pl->dx1;
dl.y = pl->dy1;
c.x = pl->x2;
c.y = pl->y2;
dc.x = pl->dx2;
dc.y = pl->dy2;
if(nsides == 0) {
s = l;
ds = dl;
}
if(dopath)
mypathsegment(&l,&dl,&c,&dc);
else
tempsegment(&l,&dl,&c,&dc);
nsides++;
pl = (pathline *)pl->next;
}
if(nsides>0 && dopath) {
if(c.x != s.x || c.y != s.y)
mypathsegment(&c,&dc,&s,&ds);
}
if(dopath)
pathclose();
else
tempclose();
}
mypathsegment(v1,dv1,v2,dv2)
vect *v1,*dv1,*v2,*dv2;
{
pathsegment(v1,dv1,v2,dv2);
}
/*
* set global properties
*
*
*/
void setflat(float flat)
{
curflatness = flat;
}
void setbevel()
{
checkpath();
freepath(bevpath);
flattenpath(curpath);
bevpath = curpath;
curpath = 0;
}
/*
* build a path structure
*
*
*/
void newpath()
{
checkpath();
}
void closepath()
{
if(curpath && curpath->tail)
lineto(startx,starty);
nsegs = 0;
}
void moveto(float x, float y)
{
startx = curx = x;
starty = cury = y;
nsegs = 0;
}
void lineto(float x, float y)
{
checkpath();
if(x != curx || y != cury) {
addline(curpath,curx,cury,x,y);
curx = x;
cury = y;
}
}
void curveto(float x1, float y1, float x2, float y2, float x3, float y3)
{
checkpath();
addcurve(curpath,curx,cury,x1,y1,x2,y2,x3,y3);
curx = x3;
cury = y3;
}
/*
* free a path
*
*/
void freepath(path *p)
{
pathseg *ps, *next;;
if(!p)
return;
switch(p->type) {
case TYPE_BUILD:
ps = p->head;
while(ps) {
next = ps->next;
free(ps);
ps = next;
}
free(p);
break;
case TYPE_STROKE:
free(p->data);
free(p);
break;
case TYPE_FILL:
case TYPE_BEVELED:
freesgiobj(p->data);
free(p);
break;
}
}
/*
* create a path using current bevel and current flatness.
*
*
*/
path *stroke()
{
pathline *pl;
path *p;
int nf, count;
float *fptr, *cptr;
checkpath();
flattenpath(curpath);
nf = nfloats(curpath);
p = (path *)mymalloc(sizeof(path));
p->type = TYPE_STROKE;
p->data=(char *)mymalloc(nf*sizeof(float));
fptr = (float*)p->data;
pl = (pathline *)curpath->head;
cptr = 0;
count = 0;
while(pl) {
nf += 2;
if(pl->attr & START_BIT) {
if(cptr) {
*cptr = count;
count = 0;
}
cptr = fptr;
fptr++;
*fptr++ = pl->x1;
*fptr++ = pl->y1;
count++;
}
*fptr++ = pl->x2;
*fptr++ = pl->y2;
count++;
pl = (pathline *)pl->next;
}
if(cptr)
*cptr = count;
*fptr++ = 0;
freepath(curpath);
curpath = 0;
return p;
}
path *fill()
{
float x, y;
vect p0, p1, s, l, c;
int nsides;
pathline *pl;
path *p;
sgiobj *obj, *tobj;
checkpath();
flattenpath(curpath);
tempbegin();
p0.x = 1.0;
p0.y = 0.0;
p1.x = 0.0;
p1.y = 0.0;
tempsegment(&p0,0,&p1,0);
entershape(curpath,1);
obj = getfaces();
p = (path *)mymalloc(sizeof(path));
p->type = TYPE_FILL;
p->data=(char *)obj;
freepath(curpath);
curpath = 0;
return p;
}
path *bevel3d()
{
vect p0, p1;
pathline *pl;
path *p;
sgiobj *obj, *fobj, *bobj, *tobj;
checkpath();
flattenpath(curpath);
if(bevpath) {
entershape(bevpath,0);
entershape(curpath,1);
fobj = getfaces();
bobj = follow();
if(fobj && bobj) {
obj = catsgiobj(fobj,bobj);
freesgiobj(fobj);
freesgiobj(bobj);
} else if(fobj)
obj = fobj;
else if(bobj)
obj = bobj;
else {
printf("no objects from getfaces and follow\n");
exit(1);
}
p = (path *)mymalloc(sizeof(path));
p->type = TYPE_BEVELED;
p->data=(char *)obj;
}
freepath(curpath);
curpath = 0;
return p;
}
/*
* actually draw a path
*
*
*/
void drawpath(path *p)
{
float *fptr;
int n;
switch(p->type) {
case TYPE_STROKE:
fptr = (float *)p->data;
n = *fptr++;
while(n>0) {
bgnline();
while(n--) {
v2f(fptr);
fptr += 2;
}
endline();
n = *fptr++;
}
break;
case TYPE_FILL:
drawsgiobj(p->data,DRAW_POINTS);
break;
case TYPE_BEVELED:
drawsgiobj(p->data,DRAW_POINTS|DRAW_NORMALS);
break;
}
}